package com.example.sample.vpn;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.text.TextUtils;
import android.util.Log;

import net.liteheaven.xblib.common.rom.ShellUtil;

import java.util.HashSet;
import java.util.List;

public class ForwardManager {

    private static final String TAG = "ForwardManager";
    private static ForwardManager mInstance = null;
    private static Context mContext = null;
    
    // 数据库相关
    private static final int VERSION = 1;
    public static final String TABLE_NAME = "forward_ip_table";
    private SQLiteDatabase mDb;

    // 是否透传
    private static final int FORWARD_UNKNOWN = 0;
    private static final int FORWARD_YES = 1;
    private static final int FORWARD_NO = 2;
    
    // 业务相关
    private HashSet<String> mPkgList = new HashSet<String>();
    private HashSet<Integer> mUidList = new HashSet<Integer>();    

    public static void setContext(Context ctx){
    	mContext = ctx;
    }
    
    public static ForwardManager getInstance(){
    	if (mContext == null){
    		throw new IllegalStateException("plz call setContext at first!");
    	}
    	
        if (mInstance == null){
            mInstance = new ForwardManager();
        }
        return mInstance;
    }

    public static void destoryInstance(){
        if (mInstance != null){
            mInstance = null;
        }
    }

    public class DBOpenHelper extends SQLiteOpenHelper{

        public DBOpenHelper(Context context, String name, CursorFactory factory, int version) {
            super(context, name, factory, version);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            createTable(db);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        }

        private void createTable(SQLiteDatabase db){
            if (db != null){
                String ifNotExistsStr = "if not exists ";
                String sqlStr = "create table " + ifNotExistsStr + TABLE_NAME
                        + "( ip text primary key ,"
                        + "forward integer"
                        + ");";
                db.execSQL(sqlStr);
            }
        }
    }

    private ForwardManager(){
        DBOpenHelper helper = new DBOpenHelper(mContext, TABLE_NAME, null, VERSION);
        mDb = helper.getWritableDatabase();
    }

    /**
     * 需要透传？
     * @param ip
     * @return
     */
    public int needForward(String ip){
        int forward = FORWARD_UNKNOWN;
        if (mDb != null){
            String [] cols = new String[]{"forward"};
            String selection = "ip=" + ip;
            Cursor cursor = mDb.query(TABLE_NAME, cols, selection, null, null, null, null);
            if (cursor.getColumnCount()>0){
                cursor.moveToFirst();
                forward = cursor.getInt(0);
            }
        }
        Log.i(TAG, "needForward "+ip+" = "+forward);
        return forward;
    }

    /**
     * 保存IP透传信息
     * @param ip
     * @param forward
     */
    public void saveForward(String ip, int forward){
        if (mDb!=null){
            ContentValues cv = new ContentValues();
            cv.put("ip", ip);
            cv.put("forward", forward);
            mDb.insert(TABLE_NAME, null, cv);
        }
        Log.i(TAG, "saveForward "+ip+" = "+forward);
    }
    
    public void setGamePkgList(HashSet<String> pkgList){
    	mPkgList = pkgList;
    }
    
    /**
     * 
     * 更新UID列表 
     * @throw 
     * @return void
     */
    public void updateUidList(){
    	
    	mUidList.clear();
    	
    	Context ctx = mContext;
    	ActivityManager am = (ActivityManager)ctx.getSystemService(Context.ACTIVITY_SERVICE);    	
    	
    	List<RunningAppProcessInfo> piList = am.getRunningAppProcesses();
        for (RunningAppProcessInfo pi : piList) {
        	
        	boolean contain = false;
        	for (String pkg : pi.pkgList) {
				if (mPkgList.contains(pkg)){
					contain = true;
					break;
				}
			}
        	
        	if (contain){
        		mUidList.add(pi.uid);
        	}        	
		}
    }
    
    public boolean isTcpGamePort(int port){

    	String hexStr = String.format("%04x", port);
    	hexStr = hexStr.toUpperCase();
    	
    	final String cmd0 = "cat /proc/net/tcp";
    	final String cmd1 = "cat /proc/net/tcp6";
    	final String cmd2 = "grep " + ":" +hexStr;
        String result = ShellUtil.execAfter(cmd0, cmd2);

        if (TextUtils.isEmpty(result)){
        	result = ShellUtil.execAfter(cmd1, cmd2);
        	if (TextUtils.isEmpty(result)){
        		return false;
        	}
        }
        
        boolean isGame = false;
        for (Integer uid : mUidList) {
			if (result.contains(""+uid)){
				isGame = true;
			}
		}    	
    	return isGame;
    }
    
    public boolean isUdpGamePort(int port){

    	String hexStr = String.format("%04x", port);
    	hexStr = hexStr.toUpperCase();
    	
    	final String cmd0 = "cat /proc/net/udp";
    	final String cmd1 = "cat /proc/net/udp6";
    	final String cmd2 = "grep " + ":" +hexStr;
        String result = ShellUtil.execAfter(cmd0, cmd2);
        if (TextUtils.isEmpty(result)){
        	result = ShellUtil.execAfter(cmd1, cmd2);
        	if (TextUtils.isEmpty(result)){
        		return false;
        	}
        }
        
        boolean isGame = false;
        for (Integer uid : mUidList) {
			if (result.contains(""+uid)){
				isGame = true;
			}
		}    	
    	return isGame;
    }
    
    /**
     * 
     * 是否是游戏UID 
     * @throw 
     * @return boolean
     */
    public boolean isGameUid(int uid){
    	
    	long startTick = System.currentTimeMillis();
    	
    	boolean ret = false;
    	
    	if (uid <= 10000){
    		ret = false;
    	}else{
    		Context ctx = mContext;
        	ActivityManager am = (ActivityManager)ctx.getSystemService(Context.ACTIVITY_SERVICE);    	
        	
        	List<RunningAppProcessInfo> piList = am.getRunningAppProcesses();
        	
        	long execInterval = System.currentTimeMillis() - startTick;
        	Log.i(TAG, "getRunningAppProcesses exec interval = " + execInterval);
        	
            for (RunningAppProcessInfo pi : piList) {        	
            	if (uid == pi.uid){
            		boolean contain = false;
                	for (String pkg : pi.pkgList) {
        				if (mPkgList.contains(pkg)){
        					contain = true;
        					break;
        				}
        			}
                	
                	if (contain){
                		ret = true;
                		break;
                	}   
            	}     	
    		}
    	}
    	
    	long execInterval = System.currentTimeMillis() - startTick;
    	Log.i(TAG, "isGameUid exec interval = " + execInterval);
    	
        return ret;    	
    }
}
